package bpce;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.Hits;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;

import plugin.bpce.Object.RepositoryObject;
import plugin.bpce.modelo.BPCEResult;
import plugin.bpce.modelo.ConfiguracaoModelo;
import plugin.bpce.modelo.DadosCoppeer;
import plugin.bpce.modelo.ModeloAvaliado;
import bpce.Entry.ConfiguracaoNovoEntry;
import bpce.Entry.ConfiguracaoNovoResultEntry;
import bpce.Entry.PontuaModeloEntry;
import bpce.Entry.PublicaModeloEntry;
import bpce.Entry.QueryEntry;
import bpce.Entry.QueryResultEntry;
import bpce.Entry.SincronizacaoEntry;
import bpce.Entry.SincronizacaoResultEntry;
import bpce.object.AgentesConhecidos;
import bpce.object.Log;
import coppeer.cell.Cell;
import coppeer.cell.CellEvent;
import coppeer.cell.CellEventListener;
import coppeer.cell.Lease;
import coppeer.cellAgent.AbstractBehavior;
import coppeer.file.httpImpl.CoppeerWebServer;
import coppeer.file.httpImpl.Response;
import coppeer.net.CoppeerWebService;
import coppeer.net.ServiceResponse;

public class BPCEBehavior extends AbstractBehavior implements CoppeerWebService {
	
	public static long SEARCH_TIME = 5000;
	private static final long serialVersionUID = -8330083007527221693L;
	
	private QueryEntry assuntoBuscado;
	private String BPCE_HOME, currentQuery, coppeerHome, nomeUsuario; 
	private Cell cell;
	private QueryResultEntry resultado;
	private BPCEResult[] resultadoBusca;
	private RepositoryObject RO;
	private boolean webserverStarted;
	private BPCEWindow window;
	private long WAIT_TIME;
	private ConfiguracaoNovoEntry confNovoEntry;
	private ConfiguracaoNovoResultEntry confNovoResultEntry;
	private ConfiguracaoModelo configuracao;
	private AgentesConhecidos agentesConhecidos;
	private PublicaModeloEntry publicaModeloEntry;
	private PontuaModeloEntry pontuaModeloEntry;
	private Log log;
	private SincronizacaoEntry sincronizacaoEntry;
	private SincronizacaoResultEntry sincronizacaoResultEntry;
	
	public void behave(){		
		int local;
		
		this.cell = getCell();		
		this.window = new BPCEWindow();	
		this.window.setTitle("BPCE Service: " + cell.getAgencyId().toString());		
		this.coppeerHome = getAgency().getProperties().getProperty("coppeerHome");		
		this.nomeUsuario = System.getProperty("user.name");
		
		local = this.coppeerHome.indexOf("file:\\\\\\");		
		
		if (local != -1)
			this.coppeerHome = this.coppeerHome.substring(local + 8, this.coppeerHome.length());
		
		this.coppeerHome = this.coppeerHome.replace("%20", " ");
		this.BPCE_HOME = this.coppeerHome + "/rep_BPCE/Index/";		
		
		if (this.webserverStarted == true) {
			this.window.setVisible(true);
			return;
		}
		
		this.window.log("Starting BPCE Service");	
		
		// Inicializa o servi�o Web.
		registerService("busca.bp",this);
		registerService("replicaConfiguracao.bp", this);
		registerService("verificaConfiguracao.bp", this);
		registerService("getDadosCoppeer.bp", this);
		registerService("publicaModelo.bp", this);
		registerService("pontuaVisualizacao.bp", this);
				
		window.log("BPCE Service started");
		// Seta a variavel informando a inicializacao do servi�o web para que
		// o mesmo nao seja inicializado novamente no futuro.
		webserverStarted = true;
		listenToEvents();
		
		try{
			synchronized(this){
				wait(5000);
			}
		}
		catch(Exception e){
			e.printStackTrace();
		}
		
 		conectaVizinhos(); 		
 		atualizaConfiguracaoInicial();
 		carregaAgentesConhecidos();
 		
 		this.RO = new RepositoryObject(this.coppeerHome, this.nomeUsuario, this.configuracao);
 		this.log = new Log(this.coppeerHome);
 		
 		sincronizaAgente();
 		
 		/*if (this.configuracao == null)
 			this.WAIT_TIME = 5000;
 		else
 			this.WAIT_TIME = Long.parseLong(this.configuracao.getTempoEsperaSincronizacao());*/
	}

	private void sincronizaAgente() {
		SincronizacaoEntry se;
		
		try{
			se = new SincronizacaoEntry();
			se.setNomeAgente(getAgency().getId().toString());
			se.setListaAgentesConhecidos(this.agentesConhecidos.getAgentesConhecidos());
			se.setCell(cell.getProxy());
			se.setListaModeladores(this.RO.getModeladores());
			se.setListaDiagramas(this.RO.getDiagramas());
			se.setListaCopiaModeladores(this.log.getCopiaModeladores());
			se.setListaCopiaDiagramas(this.log.getCopiaDiagramas());
			se.setListaLog(this.log.getLogs());
			
			this.cell.write(se, null, 10000);
		}
		catch(Exception e){
			e.printStackTrace();
		}
	}

	private void carregaAgentesConhecidos() {
		FileInputStream fis;
		ObjectInputStream ois;
		
		try{
			fis = new FileInputStream(this.coppeerHome + "/rep_BPCE/agentesConhecidos.dat");
			ois = new ObjectInputStream(fis);
			
			this.agentesConhecidos = (AgentesConhecidos) ois.readObject();
			
			ois.close();
			fis.close();
		}
		catch(Exception e){
			this.agentesConhecidos = new AgentesConhecidos();
		}
		
	}

	private void atualizaConfiguracaoInicial() {
		FileInputStream fis;
		ConfiguracaoNovoEntry cne;
		boolean configExiste;
		ObjectInputStream ois;
		
		try{
			fis = new FileInputStream(this.coppeerHome + "/rep_BPCE/configuracao.dat");
			ois = new ObjectInputStream(fis);
			
			this.configuracao = (ConfiguracaoModelo) ois.readObject();
			
			ois.close();
			fis.close();
			configExiste = true;
		}
		catch(Exception e){
			configExiste = false;
		}
		
		if (! configExiste){
			cne = new ConfiguracaoNovoEntry();
			cne.setAgente(getAgency().getId().toString());
			try{
				cell.write(cne, null, 10);
			}
			catch(Exception e){
				e.printStackTrace();
			}
		}
	}

	private synchronized void conectaVizinhos() {
		Collection agencies, vizinhos;
		Iterator it;
		String vizinho;
		Object obj;
		boolean conecta = false;

		try{
			agencies = getKnownAgencies();
			vizinhos = cell.getNeighbors();
			
			if (agencies != null){
				it = agencies.iterator();
				while(it.hasNext()){
					obj = it.next();
					vizinho = (String) obj;
					
					if ((vizinhos != null) && !(vizinhos.contains(obj)))
						conecta = true;
					else if (vizinhos == null)
						conecta = true;
					
					if (conecta)
						cell.connect(createAgencyId(vizinho));
				}
			}		
			
		}
		catch(Exception e){
			e.printStackTrace();			
		}		
	}

	public void handleCellEvent(CellEvent cellEvent){
		String handBack;
		QueryEntry qey;
		QueryResultEntry qrey;		
		ConfiguracaoNovoEntry cne;
		ConfiguracaoNovoResultEntry cnre;
		PublicaModeloEntry pme;
		PontuaModeloEntry ptoe;
		SincronizacaoEntry se;
		SincronizacaoResultEntry sre;
		
		try{
			handBack = (String) cellEvent.getRegistrationObject();
			
			if (handBack.equals("query")){
				qey = (QueryEntry) this.cell.takeIfExists(this.assuntoBuscado, null, 0);
				if (qey != null)
					handleQueryEntry(qey);
			}
			else if (handBack.equals("queryResult")){
				qrey = (QueryResultEntry) this.cell.takeIfExists(this.resultado, null, 0);
				if (qrey != null)
					handleQueryResultEntry(qrey);
			}
			else if (handBack.equals("configNovoEntry")){
				cne = (ConfiguracaoNovoEntry) this.cell.takeIfExists(this.confNovoEntry, null, 0);
				if (cne != null)
					handleConfiguracaoNovoEntry(cne);
			}
			else if (handBack.equals("configNovoResultEntry")){
				cnre = (ConfiguracaoNovoResultEntry) this.cell.takeIfExists(this.confNovoResultEntry, null, 0);
				if (cnre != null)
					handleConfiguracaoNovoResultEntry(cnre);
			}
			else if (handBack.equals("publicaModeloEntry")){
				pme = (PublicaModeloEntry) this.cell.takeIfExists(this.publicaModeloEntry, null, 0);
				if(pme != null)
					handlePublicaModeloEntry(pme);
			}
			else if (handBack.equals("pontuaModeloEntry")){
				ptoe = (PontuaModeloEntry) this.cell.takeIfExists(this.pontuaModeloEntry, null, 0);
				if(ptoe != null)
					handlePontuaModeloEntry(ptoe);
			}
			else if (handBack.equalsIgnoreCase("sincronizacaoEntry")){
				se = (SincronizacaoEntry) this.cell.takeIfExists(this.sincronizacaoEntry, null, 0);
				if (se != null)
					handleSincronizacaoEntry(se);
			}
			else if (handBack.equalsIgnoreCase("sincronizacaoResultEntry")){
				sre = (SincronizacaoResultEntry) this.cell.take(this.sincronizacaoResultEntry, null, 0);
				if (sre != null)
					handleSincronizacaoResultEntry(sre);
			}
		}
		catch(Exception e){
			e.printStackTrace();
		}
	}
	
	private void handleSincronizacaoResultEntry(SincronizacaoResultEntry sre) {
		this.agentesConhecidos.mergeAgentes(sre.getListaAgentesConhecidos());
		gravaAgentesConhecidos();
		
		this.RO.mergePontuacaoModelos(sre.getListaModeladores(), sre.getListaDiagramas());
	}

	private void handleSincronizacaoEntry(SincronizacaoEntry se) {		
		Cell response;
		SincronizacaoResultEntry sre;
		
		this.agentesConhecidos.mergeAgentes(se.getListaAgentesConhecidos());
		gravaAgentesConhecidos();
		
		this.RO.mergePontuacaoModelos(se.getListaModeladores(), se.getListaDiagramas());
		this.log.sincronizaLogs(se.getListaLog(), se.getListaCopiaModeladores(), se.getListaCopiaDiagramas(), getAgency().getId().toString());
		
		try{
			response = se.getCell();
			sre = new SincronizacaoResultEntry();
			sre.setListaAgentesConhecidos(this.agentesConhecidos.getAgentesConhecidos());
			sre.setListaModeladores(this.RO.getModeladores());
			sre.setListaDiagramas(this.RO.getDiagramas());
			response.write(sre, null, 10000);
		}
		catch(Exception e){
			e.printStackTrace();
		}
	}

	private void handlePontuaModeloEntry(PontuaModeloEntry pme) {
		int seqAlteracao;
		
		seqAlteracao = this.agentesConhecidos.getNextSeqAlteracao(pme.getNomeAgente());
		
		if (seqAlteracao == pme.getSeqAlteracao()){
			this.agentesConhecidos.addAgente(pme.getNomeAgente());
			this.agentesConhecidos.incrementaAlteracao(pme.getNomeAgente());
			gravaAgentesConhecidos();

			geraLogPontuacao(pme.getNomeModelo(), pme.getNomeAutor(), pme.getNomePontuador(), pme.getData());
			this.RO.pontuaModelo(pme.getNomeModelo(), pme.getNomeAutor(), pme.getNomePontuador(), pme.getIndice(), pme.getTipoPontuacao());
		}		
	}

	private void handlePublicaModeloEntry(PublicaModeloEntry pme) {
		int seqAlteracao;
		String avaliou;
		
		seqAlteracao = this.agentesConhecidos.getNextSeqAlteracao(pme.getNomeAgente());
		
		if (seqAlteracao == pme.getSeqAlteracao()){
			this.agentesConhecidos.addAgente(pme.getNomeAgente());
			this.agentesConhecidos.incrementaAlteracao(pme.getNomeAgente());
			
			if (pme.getAvaliou())
				avaliou = "1";
			else
				avaliou = "0";

			geraLogPublicacao(pme.getNomeAutor(), pme.getNomeDiagrama(), avaliou, pme.getListaModeloAvaliado(), pme.getData());
			this.RO.publicaModelo(pme.getNomeDiagrama(), pme.getNomeAutor(), pme.getAvaliou(), pme.getNomeAgente(), pme.getListaModeloAvaliado());		
			
			gravaAgentesConhecidos();
		}
	}
	
	private synchronized void geraLogPublicacao(String nomeAutor, String nomeDiagrama, String avaliou, List<ModeloAvaliado> listaModeloAvaliado, Long data){
		List<String> agentesDesconectados;
		
		agentesDesconectados = verificaAgentesDesconectados(this.agentesConhecidos.getAgentesConhecidos());
		agentesDesconectados.remove(getAgency().getId().toString());
		
		if (agentesDesconectados.size() > 0){
			if (! this.log.existeLog()){
				this.log.copiaModeladores(this.RO.getModeladores(), this.RO.getDiagramas());
			}

			this.log.geraLogPublicacao(nomeAutor, nomeDiagrama, avaliou, listaModeloAvaliado, agentesDesconectados, data);
		}
	}

	private void handleConfiguracaoNovoResultEntry(ConfiguracaoNovoResultEntry cnre) {
		ConfiguracaoModelo conf;
		FileOutputStream out;
		ObjectOutputStream outObjeto;
		
		conf = cnre.getConfiguracao();
		
		try{
			out = new FileOutputStream(this.coppeerHome + "/rep_BPCE/configuracao.dat");
			outObjeto = new ObjectOutputStream(out);
			outObjeto.writeObject(conf);
			outObjeto.flush();
			outObjeto.close();
			
			this.configuracao = conf;
			this.RO.setConfiguracao(conf);
		}
		catch(Exception e){
			e.printStackTrace();
		}		
	}

	private void handleConfiguracaoNovoEntry(ConfiguracaoNovoEntry cne) {
		ConfiguracaoModelo conf;
		FileOutputStream out;
		ObjectOutputStream outObjeto;
		ConfiguracaoNovoResultEntry cnre;
		
		conf = cne.getConfiguracao();
		if (conf != null){
			try{
				out = new FileOutputStream(this.coppeerHome + "/rep_BPCE/configuracao.dat");
				outObjeto = new ObjectOutputStream(out);
				outObjeto.writeObject(conf);
				outObjeto.flush();
				outObjeto.close();
				
				this.configuracao = conf;
				this.RO.setConfiguracao(conf);
			}
			catch(Exception e){
				e.printStackTrace();
			}
		}
		else{
			try{
				cnre = new ConfiguracaoNovoResultEntry();
				cnre.setAgente(cne.getAgente());
				cnre.setConfiguracao(this.configuracao);
				
				cell.write(cnre, null, 100);
			}
			catch(Exception e){
				e.printStackTrace();
			}
		}
	}

	private void handleQueryEntry(QueryEntry queryEntry){
		Cell queryCell;
		String Assunto;
		QueryResultEntry queryResultEntry;
		BPCEResult[] ResultadoBusca;
		
		queryCell = queryEntry.getCell();
		Assunto = queryEntry.getAssunto();
		
		queryResultEntry = new QueryResultEntry();
		queryResultEntry.setQuery(Assunto);
		queryResultEntry.setAgency(this.cell.getAgencyId());
		
		ResultadoBusca = searchLocal(Assunto);
		
		queryResultEntry.setBPCEREsult(ResultadoBusca);
		
		try{
			queryCell.write(queryResultEntry, null, 10000);
		}
		catch(Exception e){
			e.printStackTrace();
		}
	}

	private void handleQueryResultEntry(QueryResultEntry queryResult){
		int tamAtual, novoTamanho, i;
		BPCEResult[] temp1, temp2;
		
		if (this.currentQuery == null)
			return;
		else if (this.currentQuery.equalsIgnoreCase(queryResult.getQuery())){
			if (this.resultadoBusca == null)
				this.resultadoBusca = queryResult.getResult();
			else{
				tamAtual = this.resultadoBusca.length;
				temp1 = queryResult.getResult();
				novoTamanho = tamAtual + temp1.length;
				temp2 = this.resultadoBusca;
				this.resultadoBusca = new BPCEResult[novoTamanho];
				
				for(i = 0; i < tamAtual; i++)
					this.resultadoBusca[i] = temp2[i];
				
				for(i = tamAtual; i < novoTamanho; i++)
					this.resultadoBusca[i] = temp1[i - tamAtual];
			}
		}
	}

	private void listenToEvents(){
		CellEventListener listener;
		
		listener = this.getListener();
		
		this.assuntoBuscado = new QueryEntry();
		this.resultado = new QueryResultEntry();
		this.confNovoEntry = new ConfiguracaoNovoEntry();
		this.confNovoResultEntry = new ConfiguracaoNovoResultEntry();
		this.publicaModeloEntry = new PublicaModeloEntry();
		this.pontuaModeloEntry = new PontuaModeloEntry();
		this.sincronizacaoEntry = new SincronizacaoEntry();
		this.sincronizacaoResultEntry = new SincronizacaoResultEntry();
		
		this.confNovoEntry.setAgente(getAgency().getId().toString());
		this.confNovoResultEntry.setAgente(getAgency().getId().toString());
		this.publicaModeloEntry.setNomeAgente(getAgency().getId().toString());
		this.pontuaModeloEntry.setNomeAgente(getAgency().getId().toString());
		this.sincronizacaoEntry.setNomeAgente(getAgency().getId().toString());
		
		try{
			cell.notify(this.assuntoBuscado, null, listener, Lease.FOREVER, "query");
			cell.notify(this.resultado, null, listener, Lease.FOREVER, "queryResult");
			cell.notify(this.confNovoEntry, null, listener, Lease.FOREVER, "configNovoEntry");
			cell.notify(this.confNovoResultEntry, null, listener, Lease.FOREVER, "configNovoResultEntry");
			cell.notify(this.publicaModeloEntry, null, listener, Lease.FOREVER, "publicaModeloEntry");		
			cell.notify(this.pontuaModeloEntry, null, listener, Lease.FOREVER, "pontuaModeloEntry");
			cell.notify(this.sincronizacaoEntry, null, listener, Lease.FOREVER, "sincronizacaoEntry");
			cell.notify(this.sincronizacaoResultEntry, null, listener, Lease.FOREVER, "sincronizacaoResultEntry");
		}
		catch(Exception e){
			e.printStackTrace();
		}			
	}	
	
	@Override
	public void onAgentCreation(Object init) {
		setName("BPCE Agent V2");
	}
	
	private ServiceResponse responseSalvaConfiguracao(Properties parms) {
		ConfiguracaoNovoEntry ce;
		ConfiguracaoModelo configuracao;
		OutputStream out;				
		ObjectOutputStream outObjeto;		
		
		configuracao = new ConfiguracaoModelo();
		configuracao.setPesoPontuacaoAvaliacao(parms.getProperty("pPtoAva"));
		configuracao.setPesoPontuacaoInicial(parms.getProperty("pPtoIni"));
		configuracao.setPesoPontuacaoVisualizacao(parms.getProperty("pPtoAva"));
		configuracao.setPontuacaoInicialDiagrama(parms.getProperty("PtoIni"));
		configuracao.setTempoEsperaSincronizacao(parms.getProperty("TimeOut"));
		
		this.agentesConhecidos.addAgente(getAgency().getId().toString());
		this.configuracao = configuracao;
		this.RO.setConfiguracao(configuracao);
		
		try{
			out = new FileOutputStream(this.coppeerHome + "/rep_BPCE/configuracao.dat");
			outObjeto = new ObjectOutputStream(out);
			outObjeto.writeObject(configuracao);
			outObjeto.flush();
			outObjeto.close();		
			
			ce = new ConfiguracaoNovoEntry();
			ce.setConfiguracao(configuracao);
			ce.setAgente(getAgency().getId().toString());			
			
			cell.removeListener(this.getListener());			 
			listenToEvents();
			cell.write(ce, null, 100);
			
			return new Response(CoppeerWebServer.HTTP_OK, CoppeerWebServer.MIME_HTML, "OK");
		}
		catch(Exception e){
			e.printStackTrace();
			return new Response(CoppeerWebServer.HTTP_NOTFOUND, CoppeerWebServer.MIME_HTML, "Erro");
		}
	}
	
	private ServiceResponse responseSearch(Properties parms){
		String assunto;
		BPCEResult[] resultadoBusca;		
		OutputStream out;				
		ObjectOutputStream outObjeto;
		File tmp;
		String path;
		Response response;
		
		assunto = parms.getProperty("assunto");
		
		this.agentesConhecidos.addAgente(getAgency().getId().toString());
		
		try{
			resultadoBusca = search(assunto);
		
			path = System.getProperty("java.io.tmpdir");
				
			tmp = new File(path);
			if (!(tmp.exists()))
				tmp.mkdir();
			
			out = new FileOutputStream(path + assunto + ".dat");
			outObjeto = new ObjectOutputStream(out);
			outObjeto.writeObject(resultadoBusca);
			outObjeto.flush();
			outObjeto.close();
			
			response =  new Response(CoppeerWebServer.HTTP_OK, CoppeerWebServer.MIME_DEFAULT_BINARY, new FileInputStream(path + assunto + ".dat"));
			
			return response;
		}
		catch(Exception e){
			e.printStackTrace();
			return new Response(CoppeerWebServer.HTTP_NOTFOUND, CoppeerWebServer.MIME_HTML, "Erro na Busca");
		}		
	}

	private BPCEResult[] search(String Assunto){
		QueryEntry queryEntry;
		
		queryEntry = new QueryEntry();
		queryEntry.setAssunto(Assunto);
		queryEntry.setCell(cell.getProxy());
		
		this.currentQuery = Assunto;
		this.resultadoBusca = null;
		
		try{
			cell.write(queryEntry, null, SEARCH_TIME);
			synchronized(this){
				wait(SEARCH_TIME);
			}
		}
		catch(Exception e){
			e.printStackTrace();
		}
		
		return this.resultadoBusca;
	}

	private synchronized BPCEResult[] searchLocal (String assunto){
		IndexReader reader;	
		IndexSearcher searcher;
		Analyzer analyzer;
		QueryParser parser;
		Query query;
		Hits hits;
		int i;
		BPCEResult[] resultadoBusca;
		Document doc;		
		Directory diretorio;
		
		try{
			diretorio = FSDirectory.getDirectory(this.BPCE_HOME);
			reader = IndexReader.open(diretorio);
			
			if (assunto == null || assunto.equalsIgnoreCase("")) {
				resultadoBusca = new BPCEResult[reader.numDocs()];
				for(i = 0; i < reader.numDocs(); i++){
					doc = reader.document(i);
					resultadoBusca[i] = new BPCEResult(doc.getField("Path").stringValue(), this.RO);
					resultadoBusca[i].setAgencyId(getAgency().getId().toString());					
				}
			}
			else{
				searcher = new IndexSearcher(reader);
				analyzer = new StandardAnalyzer();
				parser = new QueryParser("Palavra", analyzer);
				query = parser.parse(assunto + "*");			
				hits = searcher.search(query);			
				resultadoBusca = new BPCEResult[hits.length()];
				
				for(i = 0; i < hits.length(); i++){
					doc = hits.doc(i);
					resultadoBusca[i] = new BPCEResult(doc.getField("Path").stringValue(), this.RO);
					resultadoBusca[i].setAgencyId(getAgency().getId().toString());
				}
			}
		}
		catch(Exception e){
			resultadoBusca = null;			
		}
		
		return resultadoBusca;
	}

	public ServiceResponse serve(String uri, String method, Properties header, Properties parms) {
		Enumeration e;
		
		// Mostra na area de log todos os parametros do Header da requisicao web
		e = header.propertyNames();
		while (e.hasMoreElements()) {
			String value = (String) e.nextElement();
			window.log("  HDR: '" + value + "' = '" + header.getProperty(value) + "'");
		}
		// Mostra na area de log todos os parametros envidados por GET ou POST
		// da requisicao web
		e = parms.propertyNames();
		while (e.hasMoreElements()) {
			String value = (String) e.nextElement();
			window.log("  PRM: '" + value + "' = '" + parms.getProperty(value) + "'");
		}
		
		window.log(uri);
		
		conectaVizinhos();
		
		if (uri.equalsIgnoreCase("/busca.bp"))
			return responseSearch(parms);
		else if (uri.equalsIgnoreCase("/replicaConfiguracao.bp"))			
			 return responseSalvaConfiguracao(parms);
		else if (uri.equalsIgnoreCase("/verificaConfiguracao.bp"))
			return responseRetornaConfiguracao();
		else if (uri.equalsIgnoreCase("/getDadosCoppeer.bp"))
			return responseRetornaDadosCoppeer();
		else if (uri.equalsIgnoreCase("/publicaModelo.bp"))
			return responsePublicaModelo(parms);
		else if (uri.equalsIgnoreCase("/pontuaVisualizacao.bp"))
			return responsePontuaVisualizacao(parms);		
		
		return null;
	}
	
	private ServiceResponse responsePontuaVisualizacao(Properties parms) {
		String nomeModelo, nomeAutor, nomePontuador;
		PontuaModeloEntry pme;
		int seqAlteracao;
		Date data;
		Long dataLong;
		
		nomeModelo = parms.getProperty("nomeModelo");
		nomeAutor = parms.getProperty("nomeAutorModelo");
		nomePontuador = parms.getProperty("nomePontuador");
		
		data = new Date();
		dataLong = data.getTime();
		
		this.agentesConhecidos.addAgente(getAgency().getId().toString());
		seqAlteracao = this.agentesConhecidos.getNextSeqAlteracao(getAgency().getId().toString());
		this.agentesConhecidos.incrementaAlteracao(getAgency().getId().toString());
		gravaAgentesConhecidos();
		
		geraLogPontuacao(nomeModelo, nomeAutor, nomePontuador, dataLong);
		this.RO.pontuaModelo(nomeModelo, nomeAutor, nomePontuador, 1, 0);
		
		try{
			pme = new PontuaModeloEntry();
			pme.setIndice(1);
			pme.setNomeAgente(getAgency().getId().toString());
			pme.setNomeAutor(nomeAutor);
			pme.setNomeModelo(nomeModelo);
			pme.setNomePontuador(nomePontuador);
			pme.setTipoPontuacao(0);
			pme.setSeqAlteracao(seqAlteracao);
			pme.setData(dataLong);
			
			cell.removeListener(this.getListener());			 
			listenToEvents();
			cell.write(pme, null, 100);
		}
		catch(Exception e){
			e.printStackTrace();
		}
		
		return null;
	}

	private synchronized void geraLogPontuacao(String nomeModelo, String nomeAutor, String nomePontuador, Long data) {
		List<String> agentesDesconectados;
		
		agentesDesconectados = verificaAgentesDesconectados(this.agentesConhecidos.getAgentesConhecidos());
		agentesDesconectados.remove(getAgency().getId().toString());
		
		if (agentesDesconectados.size() > 0){
			if (! this.log.existeLog()){
				this.log.copiaModeladores(this.RO.getModeladores(), this.RO.getDiagramas());
			}

			this.log.geraLogPontuacao(nomeAutor, nomeModelo, nomePontuador, agentesDesconectados, data);
		}
	}

	private ServiceResponse responsePublicaModelo(Properties parms) {		
		String nomeDiagrama, nomeAutor, temp, uDiagrama, uAutor, uAvaliacao;
		boolean avaliou;
		List<ModeloAvaliado> listaModeloAvaliado;
		ModeloAvaliado modelo;
		int i, seqAlteracao;
		PublicaModeloEntry pme;		
		Date data;
		Long dataLong;
		
		nomeDiagrama = parms.getProperty("NomeDiagrama");
		nomeAutor = parms.getProperty("NomeAutor");
		temp = parms.getProperty("Avaliou");
		listaModeloAvaliado = new ArrayList<ModeloAvaliado>();
		
		if (temp.equals("1")){
			avaliou = true;						
			i = 0;
			
			while(true){
				uDiagrama = parms.getProperty("uDiagrama" + Integer.toString(i));
				
				if (uDiagrama == null)				
					break;
				
				uAutor = parms.getProperty("uAutor" + Integer.toString(i));
				uAvaliacao = parms.getProperty("uAvaliacao" + Integer.toString(i));
				
				modelo = new ModeloAvaliado();
				modelo.setNomeAutor(uAutor);
				modelo.setNomePontuador(nomeAutor);
				modelo.setNomeModelo(uDiagrama);
				modelo.setPontuacao(Integer.parseInt(uAvaliacao));
				
				listaModeloAvaliado.add(modelo);
				
				i++;
			}
		}
		else
			avaliou = false;
		
		this.agentesConhecidos.addAgente(getAgency().getId().toString());
		seqAlteracao = this.agentesConhecidos.getNextSeqAlteracao(getAgency().getId().toString());
		this.agentesConhecidos.incrementaAlteracao(getAgency().getId().toString());		
		gravaAgentesConhecidos();
		
		data = new Date();
		dataLong = data.getTime();		
		geraLogPublicacao(nomeAutor, nomeDiagrama, temp, listaModeloAvaliado, dataLong);
		
		this.RO.publicaModelo(nomeDiagrama, nomeAutor, avaliou, getAgency().getId().toString(), listaModeloAvaliado);		
		
		try{
			pme = new PublicaModeloEntry();			
			pme.setAvaliou(avaliou);
			pme.setListaModeloAvaliado(listaModeloAvaliado);
			pme.setNomeAgente(getAgency().getId().toString());
			pme.setNomeAutor(nomeAutor);
			pme.setNomeDiagrama(nomeDiagrama);
			pme.setSeqAlteracao(seqAlteracao);
			pme.setData(dataLong);
			
			cell.removeListener(this.getListener());			 
			listenToEvents();
			cell.write(pme, null, 100);			
		}
		catch(Exception e){
			e.printStackTrace();
		}
		
		return null;
	}

	private synchronized List<String> verificaAgentesDesconectados(List<String> agentesConhecidos){
		List<String> retorno;
		int i;
		Cell tmp;		
		
		retorno = new ArrayList<String>();
		
		try{
			for(i = 0; i < agentesConhecidos.size(); i++){
				tmp = this.cell.getNeighbor(createAgencyId(agentesConhecidos.get(i)));
				
				if (tmp == null){
					retorno.add(agentesConhecidos.get(i));
				}
			}
		}
		catch(Exception e){
			e.printStackTrace();
		}
		
		return retorno;
	}

	private synchronized void gravaAgentesConhecidos() {
		OutputStream out;				
		ObjectOutputStream outObjeto;
		
		try{
			out = new FileOutputStream(this.coppeerHome + "/rep_BPCE/agentesConhecidos.dat");
			outObjeto = new ObjectOutputStream(out);
			outObjeto.writeObject(this.agentesConhecidos);
			outObjeto.flush();
			outObjeto.close();
		}
		catch(Exception e){
			e.printStackTrace();
		}
	}

	private ServiceResponse responseRetornaDadosCoppeer() {
		DadosCoppeer dados;
		String path;
		FileOutputStream fos;
		ObjectOutputStream oos;

		try{
			dados = new DadosCoppeer();
			dados.setConfiguracao(configuracao);
			dados.setAgente(getAgency().getId().toString());
			dados.setCoppeerHome(coppeerHome);
			dados.setNomeUsuario(this.nomeUsuario);
			
			path = System.getProperty("java.io.tmpdir");
			
			fos = new FileOutputStream(path + "dados.dat");
			oos = new ObjectOutputStream(fos);
			oos.writeObject(dados);
			oos.flush();
			oos.close();
			
			return new Response(CoppeerWebServer.HTTP_OK, CoppeerWebServer.MIME_DEFAULT_BINARY, new FileInputStream(path + "dados.dat"));
		}
		catch(Exception e){			
			return new Response(CoppeerWebServer.HTTP_OK, CoppeerWebServer.MIME_DEFAULT_BINARY, "");
		}		
	}

	private ServiceResponse responseRetornaConfiguracao() {
		FileInputStream fis;
		ObjectInputStream ois;
		@SuppressWarnings("unused")
		ConfiguracaoModelo conf;
		
		try{
			fis = new FileInputStream(this.coppeerHome + "/rep_BPCE/configuracao.dat");
			ois = new ObjectInputStream(fis);
			conf = (ConfiguracaoModelo) ois.readObject();
			ois.close();
			fis.close();
			
			return new Response(CoppeerWebServer.HTTP_OK, CoppeerWebServer.MIME_DEFAULT_BINARY, new FileInputStream(this.coppeerHome + "/rep_BPCE/configuracao.dat"));
		}
		catch(Exception e){			
			return new Response(CoppeerWebServer.HTTP_OK, CoppeerWebServer.MIME_DEFAULT_BINARY, "");
		}		
	}
}